package com.smartian.v2;

import android.text.TextUtils;

import com.smartian.v2.model.DateTimeNode;
import com.smartian.v2.model.ScheduleTaskBean;
import com.smartian.v2.utils.DateTimeHelper;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by tianweitong on 2020/3/13.
 */

public abstract class AbstractTextParser {

    private String sourceText;
    private String repeatText;
    private int repeatTextIndex;

    public AbstractTextParser(String sourceText, String repeatText, int repeatTextIndex) {
        super();
        this.sourceText = sourceText;
        this.repeatText = repeatText;
        this.repeatTextIndex = repeatTextIndex;
    }

    public int getRepeatTextIndex() {
        return repeatTextIndex;
    }

    public String getRepeatText() {
        return repeatText;
    }

    public String getSourceText() {
        return sourceText;
    }

    public abstract ScheduleTaskBean getScheduleTaskBean();

    public abstract boolean isValid();

    public abstract String getDateTimeFormat();


    protected List<DateTimeNode> parseDate(String sourceText) {

        final List<DateTimeNode> dateTimeNodes = new ArrayList<>();

        Matcher matcher = TextPattern.REG_EXP_DATE_LEVEL_1.matcher(sourceText);
        while (matcher.find()) {
            DateTimeNode dateTimeNode = new DateTimeNode();
            String group = matcher.group();
            String resultText = DateTimeHelper.dateNumberTextToNumber(group);
            if (TextUtils.isEmpty(resultText)) continue;

            Matcher dateTextMater = TextPattern.REG_EXP_DATE_LEVEL_3.matcher(group);
            while (dateTextMater.find()) {
                group = dateTextMater.group();
            }
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;

            dateTimeNodes.add(dateTimeNode);
        }


        matcher = TextPattern.REG_EXP_TODAY.matcher(sourceText);
        while (matcher.find()) {
            DateTimeNode dateTimeNode = new DateTimeNode();
            String group = matcher.group();
            String resultText = DateTimeHelper.getToday();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;

            dateTimeNodes.add(dateTimeNode);
        }

        matcher = TextPattern.REG_EXP_TODAY.matcher(sourceText);
        while (matcher.find()) {
            DateTimeNode dateTimeNode = new DateTimeNode();
            String group = matcher.group();
            String resultText = DateTimeHelper.getToday();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;

            dateTimeNodes.add(dateTimeNode);
        }

        matcher = TextPattern.REG_EXP_TOMORROW.matcher(sourceText);
        while (matcher.find()) {
            DateTimeNode dateTimeNode = new DateTimeNode();
            String group = matcher.group();
            String resultText = DateTimeHelper.getTomorrow();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;

            dateTimeNodes.add(dateTimeNode);
        }

        matcher = TextPattern.REG_EXP_TOMORROW_TOMORROW.matcher(sourceText);
        while (matcher.find()) {
            DateTimeNode dateTimeNode = new DateTimeNode();
            String group = matcher.group();
            String resultText = DateTimeHelper.getTomorrowTomorrow();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;

            dateTimeNodes.add(dateTimeNode);
        }
        Map<String, Long> UNIT_MAP = new HashMap<>();

        UNIT_MAP.put(TextPattern.WORD_DAY_ALIAS_2, 60 * 60 * 24l);
        UNIT_MAP.put(TextPattern.WORD_DAY, 60 * 60 * 24l);
        UNIT_MAP.put(TextPattern.WORD_DAY_ALIAS, 60 * 60 * 24l);
        UNIT_MAP.put(TextPattern.WORD_WEEK, 7 * 60 * 60 * 24l);
        UNIT_MAP.put(TextPattern.WORD_WEEK_ALIAS_1, 7 * 60 * 60 * 24l);
        UNIT_MAP.put(TextPattern.WORD_WEEK_ALIAS_2, 7 * 60 * 60 * 24l);
        UNIT_MAP.put(TextPattern.WORD_MONTH_UNIT, 30 * 60 * 60 * 24l);
        UNIT_MAP.put(TextPattern.WORD_MONTH, 30 * 60 * 60 * 24l);

        for (Map.Entry<String, Long> entry : UNIT_MAP.entrySet()) {

            String unitName = entry.getKey();
            long unitValue = entry.getValue();  //两天后
            matcher = Pattern.compile(String.format(TextPattern.WORD_NEXT_PATTERN, unitName)).matcher(sourceText);
            while (matcher.find()) {
                String numStr = matcher.group();
                for (int i = 0; i < TextPattern.CHINESE_WORD_NUMBER.length; i++) {
                    numStr = numStr.replaceAll(TextPattern.CHINESE_WORD_NUMBER[i], String.valueOf(i));
                }

                for (int i = 0; i < TextPattern.LOCAL_CHINESE_NUMBER_WORD.length; i++) {
                    numStr = numStr.replaceAll(TextPattern.LOCAL_CHINESE_NUMBER_WORD[i], String.valueOf(i + 1));
                }

                if (numStr.startsWith(TextPattern.TOMORROW)) {
                    numStr = TextPattern.WORD_TWO_DAY + numStr.substring(2);
                }

                Matcher twoPattern = Pattern.compile("两(天|日|月|周|年){1}").matcher(numStr);
                while (twoPattern.find()) {
                    String group = twoPattern.group();
                    String newGroup = group.replace(TextPattern.WORD_LOCAL_LIANG, "2");
                    numStr = numStr.replaceAll(group, newGroup);
                }

                numStr = numStr.replaceAll(TextPattern.NEXT_MONTH_WORD, TextPattern.WORD_TWO_YEAR);
                numStr = numStr.replaceAll(TextPattern.NEXT_WEEK_WORD, "2星期");
                numStr = numStr.replaceAll(TextPattern.NEXT_YEAR_WORD, "2年");
                numStr = numStr.replaceAll(TextPattern.WORD_THIS_MONTH, "1月");
                numStr = numStr.replaceAll(TextPattern.WORD_THIS_YEAR, "1年");

                numStr = DateTimeHelper.replaceChineseNumberToArbirc(numStr);

                String number = DateTimeHelper.readFirstNumber(numStr);
                if (!TextUtils.isDigitsOnly(number)) continue;

                long timeVal = Integer.parseInt(number);
                long weektime = System.currentTimeMillis() + timeVal * unitValue * 1000;

                DateTimeNode dateTimeNode = new DateTimeNode();
                String group = matcher.group();
                dateTimeNode.text = group;
                dateTimeNode.index = matcher.start();
                dateTimeNode.resultText = TextPattern.sDateFormat.format(weektime);

                dateTimeNodes.add(dateTimeNode);
            }
        }

        matcher = TextPattern.REG_EXP_WEEK_DATE.matcher(sourceText);
        while (matcher.find()) {
            String group = matcher.group();
            if (TextUtils.isEmpty(group)) continue;

            String dayOfWeek = String.valueOf(group.charAt(group.length() - 1));

            if (dayOfWeek.equals(TextPattern.WORD_DAY) || dayOfWeek.equals(TextPattern.WORD_DAY_ALIAS_2)) {
                dayOfWeek = "7";
            }
            if (dayOfWeek.equals(TextPattern.WORD_END_ALIAS)) {
                dayOfWeek = "6";
            }

            for (int i = 0; i < TextPattern.CHINESE_WORD_NUMBER.length; i++) {
                if (dayOfWeek.equals(TextPattern.CHINESE_WORD_NUMBER[i])) {
                    dayOfWeek = String.valueOf(i);
                }
            }

            String weekDay = DateTimeHelper.readFirstNumber(dayOfWeek);
            if (TextUtils.isEmpty(weekDay) || !TextUtils.isDigitsOnly(weekDay)) continue;

            String date = DateTimeHelper.makeWeekToDate(weekDay);

            DateTimeNode dateTimeNode = new DateTimeNode();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = date;

            dateTimeNodes.add(dateTimeNode);
        }
        return dateTimeNodes;
    }


    protected void locatorTimeNode(List<DateTimeNode> timeNodes, List<DateTimeNode> locatorNodes) {
        for (int i = 0; i < timeNodes.size(); i++) {
            DateTimeNode dateTimeNode = timeNodes.get(i);
            for (int j = locatorNodes.size() - 1; j >= 0; j--) {
                DateTimeNode locator = locatorNodes.get(j);
                if (locator.index < dateTimeNode.index) {
                    handleTimeLocator(locator, dateTimeNode);
                    break;
                }
            }
        }

        if (timeNodes.size() != 0 || locatorNodes.size() == 0) return;
        String textTime = null;
        DateTimeNode lastLocator = locatorNodes.get(locatorNodes.size() - 1);
        Calendar calendar = Calendar.getInstance();
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);

        for (int i = 0; i < TextPattern.TIME_APM_LOCATOR.length; i++) {
            String[] locatorTexts = TextPattern.TIME_APM_LOCATOR[i];
            for (int j = 0; j < locatorTexts.length; j++) {
                if (!locatorTexts[j].equals(lastLocator.text)) {
                    continue;
                }

                if (i == 0) {
                    if (hour < 8) {
                        textTime = String.format("%s:%s", hour, minute);
                    } else {
                        textTime = "1:00";
                    }
                } else if (i == 1) {
                    if (hour > 7 && hour < 12) {
                        textTime = String.format("%s:%s", hour, minute);
                    } else {
                        textTime = "8:00";
                    }
                } else if (i == 2) {
                    textTime = "12:00";
                } else if (i == 3) {
                    if (hour > 12 && hour < 20) {
                        textTime = String.format("%s:%s", hour, minute);
                    } else {
                        textTime = "14:00";
                    }
                } else {
                    if (hour > 19) {
                        textTime = String.format("%s:%s", hour, minute);
                    } else {
                        textTime = "20:00";
                    }
                }

            }
        }

        if (TextUtils.isEmpty(textTime)) return;

        DateTimeNode dateTimeNode = new DateTimeNode();
        dateTimeNode.text = lastLocator.text;
        dateTimeNode.index = lastLocator.index;
        dateTimeNode.resultText = textTime;
        dateTimeNode.locatorText = lastLocator.text;
        dateTimeNode.type = DateTimeNode.TYPE_TIME;

        timeNodes.add(dateTimeNode);

    }

    //"凌晨"; #小于8点
    // "上午|早上|早晨|晌午|今早|明早|早餐时间"; 8-12
    // "中午"; 12
    // "下午|午后";13-19
    //"晚上|傍晚|今夜|今晚|明晚"; 20

    protected void handleTimeLocator(DateTimeNode locator, DateTimeNode dateTimeNode) {

        String text = locator.text;
        String hour = DateTimeHelper.readPrevNumberAtFlag(dateTimeNode.resultText, ":");
        String minutes = DateTimeHelper.readNextNumberAtFlag(dateTimeNode.resultText, ":");

        for (int i = 0; i < TextPattern.TIME_APM_LOCATOR.length; i++) {
            String[] locatorTexts = TextPattern.TIME_APM_LOCATOR[i];
            for (int j = 0; j < locatorTexts.length; j++) {

                if (!text.equals(locatorTexts[j])) {
                    continue;
                }

                dateTimeNode.locatorText = locatorTexts[j];

                if (i == 0) {
                    if (!TextUtils.isEmpty(hour)) {
                        int hourNum = DateTimeHelper.getIntegerValue(hour);
                        if (hourNum > 12) {
                            hour = String.format("%s", hourNum - 12);
                        }
                    } else if (TextUtils.isEmpty(hour) && TextUtils.isEmpty(minutes)) {
                        hour = "1";
                        minutes = "0";
                    }
                } else if (i == 1) {
                    if (!TextUtils.isEmpty(hour)) {
                        int hourNum = DateTimeHelper.getIntegerValue(hour);
                        if (hourNum >= 20) {
                            hour = "8";
                        }
                    } else if (TextUtils.isEmpty(hour) && TextUtils.isEmpty(minutes)) {
                        hour = "8";
                        minutes = "0";
                    }
                } else if (i == 2) {
                    if (TextUtils.isEmpty(hour) && TextUtils.isEmpty(minutes)) {
                        hour = "12";
                        minutes = "0";
                    } else if (!TextUtils.isEmpty(hour)) {
                        int hourNum = DateTimeHelper.getIntegerValue(hour);
                        if (hourNum <= 3) {
                            hour = String.format("%s", (hourNum + 12));
                            ;
                        }
                    }
                } else if (i == 3) {
                    if (!TextUtils.isEmpty(hour)) {
                        int hourNum = DateTimeHelper.getIntegerValue(hour);
                        if (hourNum < 12) {
                            hour = String.format("%s", hourNum + 12);
                        }
                    } else if (TextUtils.isEmpty(hour) && TextUtils.isEmpty(minutes)) {
                        hour = "14";
                        minutes = "0";
                    }
                } else {
                    if (!TextUtils.isEmpty(hour)) {
                        int hourNum = DateTimeHelper.getIntegerValue(hour);
                        if (hourNum < 12) {
                            hour = String.format("%s", hourNum + 12);
                        }
                    } else if (TextUtils.isEmpty(hour) && TextUtils.isEmpty(minutes)) {
                        hour = "20";
                        minutes = "0";
                    }
                }

            }

        }
        dateTimeNode.resultText = String.format("%s:%s", hour, minutes);
    }

    protected List<DateTimeNode> parseTimeLocator(String text) {

        List<DateTimeNode> dateTimeNodes = new ArrayList<>();
        if (TextUtils.isEmpty(text)) return dateTimeNodes;

        for (int i = 0; i < TextPattern.TIME_APM_LOCATOR.length; i++) {

            String[] locators = TextPattern.TIME_APM_LOCATOR[i];
            for (int j = 0; j < locators.length; j++) {
                int lastIndex = text.lastIndexOf(locators[j]);

                if (-1 != lastIndex) {
                    DateTimeNode dateTimeNode = new DateTimeNode();
                    dateTimeNode.text = locators[j];
                    dateTimeNode.index = lastIndex;
                    dateTimeNode.resultText = "";
                    dateTimeNode.type = DateTimeNode.TYPE_LOCATOR;
                    dateTimeNodes.add(dateTimeNode);
                }
            }
        }

        return dateTimeNodes;
    }

    public List<DateTimeNode> parseTime(String sourceText) {

        final List<DateTimeNode> dateTimeNodes = new ArrayList<>();
        Matcher matcher = TextPattern.REG_EXP_TIME_1.matcher(sourceText);

        while (matcher.find()) {
            String group = matcher.group();
            String resultText = DateTimeHelper.timeNumberToNumber(group);

            if (TextUtils.isEmpty(resultText)) continue;

            DateTimeNode dateTimeNode = new DateTimeNode();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;
            dateTimeNode.type = DateTimeNode.TYPE_TIME;

            dateTimeNodes.add(dateTimeNode);

        }

        matcher = TextPattern.REG_EXP_TIME_2.matcher(sourceText);
        while (matcher.find()) {
            String group = matcher.group();
            String resultText = DateTimeHelper.timeNumberToNumber(group);
            if (TextUtils.isEmpty(resultText)) continue;

            DateTimeNode dateTimeNode = new DateTimeNode();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;
            dateTimeNode.type = DateTimeNode.TYPE_TIME;

            dateTimeNodes.add(dateTimeNode);

        }

        matcher = TextPattern.REG_EXP_TIME_2.matcher(sourceText);
        while (matcher.find()) {
            String group = matcher.group();
            String resultText = DateTimeHelper.timeNumberToNumber(group);
            if (TextUtils.isEmpty(resultText)) continue;

            DateTimeNode dateTimeNode = new DateTimeNode();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;
            dateTimeNode.type = DateTimeNode.TYPE_TIME;

            dateTimeNodes.add(dateTimeNode);


        }
        matcher = TextPattern.REG_EXP_TIME_3.matcher(sourceText);
        while (matcher.find()) {

            String group = matcher.group();
            String resultText = DateTimeHelper.fourPiceTimeNumberToNumber(group);
            if (TextUtils.isEmpty(resultText)) continue;

            DateTimeNode dateTimeNode = new DateTimeNode();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;

            dateTimeNode.type = DateTimeNode.TYPE_TIME;

            dateTimeNodes.add(dateTimeNode);

        }
        matcher = TextPattern.REG_EXP_TIME_4.matcher(sourceText);
        while (matcher.find()) {

            String group = matcher.group();
            String resultText = DateTimeHelper.fourPiceTimeNumberToNumber(group);
            if (TextUtils.isEmpty(resultText)) continue;

            DateTimeNode dateTimeNode = new DateTimeNode();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;
            dateTimeNode.type = DateTimeNode.TYPE_TIME;

            dateTimeNodes.add(dateTimeNode);
        }
        matcher = TextPattern.REG_EXP_TIME_5.matcher(sourceText);
        while (matcher.find()) {

            String group = matcher.group();
            String resultText = DateTimeHelper.entireTimeNumberToNumber(group);
            if (TextUtils.isEmpty(resultText)) continue;

            DateTimeNode dateTimeNode = new DateTimeNode();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = resultText;
            dateTimeNode.type = DateTimeNode.TYPE_TIME;
            dateTimeNodes.add(dateTimeNode);
        }

        matcher = TextPattern.REG_EXP_TIME.matcher(sourceText);
        while (matcher.find()) {
            String group = matcher.group();
            if (TextUtils.isEmpty(group)) continue;
            DateTimeNode dateTimeNode = new DateTimeNode();
            dateTimeNode.text = group;
            dateTimeNode.index = matcher.start();
            dateTimeNode.resultText = group;
            dateTimeNode.type = DateTimeNode.TYPE_TIME;
            dateTimeNodes.add(dateTimeNode);
        }

        SimpleDateFormat sdf = (SimpleDateFormat) DateFormat.getInstance();
        sdf.applyPattern("HH:mm");

        Map<String, Long> UNIT_MAP = new HashMap<>();

        UNIT_MAP.put(TextPattern.WORD_MINUTE_ALIAS, 60l);
        UNIT_MAP.put(TextPattern.WORD_SECOND, 1l);
        UNIT_MAP.put(TextPattern.WORD_HOUR_UNIT, 60 * 60l);
        UNIT_MAP.put(TextPattern.WORD_15_MINUTES, 15l);

        for (Map.Entry<String, Long> entry : UNIT_MAP.entrySet()) {
            String unitName = entry.getKey();
            long unitValue = entry.getValue();  //两天后
            matcher = Pattern.compile(String.format(TextPattern.WORD_NEXT_PATTERN, unitName)).matcher(sourceText);
            while (matcher.find()) {
                String numStr = matcher.group();
                for (int i = 0; i < TextPattern.CHINESE_WORD_NUMBER.length; i++) {
                    numStr = numStr.replaceAll(TextPattern.CHINESE_WORD_NUMBER[i], String.valueOf(i));
                }

                for (int i = 0; i < TextPattern.LOCAL_CHINESE_NUMBER_WORD.length; i++) {
                    numStr = numStr.replaceAll(TextPattern.LOCAL_CHINESE_NUMBER_WORD[i], String.valueOf(i + 1));
                }

                long weektime = 0;
                if (numStr.startsWith(TextPattern.WORD_TIME_MINUTE_HALE)) {
                    float timeVal = 0.5f;
                    weektime = (long) (System.currentTimeMillis() + timeVal * unitValue * 1000);
                } else if (numStr.startsWith(TextPattern.WORD_TIME_HOUR_HALE)) {
                    float timeVal = 0.5f;
                    weektime = (long) (System.currentTimeMillis() + timeVal * unitValue * 1000);
                } else {
                    numStr = DateTimeHelper.replaceChineseNumberToArbirc(numStr);

                    String number = DateTimeHelper.readFirstNumber(numStr);
                    if (!TextUtils.isDigitsOnly(number)) continue;

                    int timeVal = Integer.parseInt(number);
                    weektime = System.currentTimeMillis() + timeVal * unitValue * 1000;
                }

                DateTimeNode dateTimeNode = new DateTimeNode();
                String group = matcher.group();
                dateTimeNode.text = group;
                dateTimeNode.index = matcher.start();
                dateTimeNode.resultText = sdf.format(weektime);

                dateTimeNode.type = DateTimeNode.TYPE_TIME;
                dateTimeNodes.add(dateTimeNode);
            }
        }
        return dateTimeNodes;
    }


    public int parseFrequent() {
        String repeatText = getRepeatText();

        String replaceText = DateTimeHelper.replaceChineseNumberToArbirc(repeatText);

        Matcher matcher = TextPattern.REG_EXP_EVERY_EXECLUDE.matcher(replaceText);
        if (matcher.find()) {
            return -1;
        }

        for (int i = 0; i < TextPattern.LOCAL_CHINESE_NUMBER_WORD.length; i++) {
            String word = TextPattern.LOCAL_CHINESE_NUMBER_WORD[i];
            replaceText = replaceText.replaceAll(word, String.valueOf(i + 1));
        }

        replaceText = replaceText.replaceAll(TextPattern.WORD_LOCAL_LIANG, String.valueOf(2));

        if (TextUtils.isEmpty(replaceText)) {
            return -1;
        }
        String number = DateTimeHelper.readFirstNumber(replaceText);
        int integerValue = DateTimeHelper.getIntegerValue(number);
        if (integerValue == 0) {
            integerValue = 1;
        }
        return integerValue;
    }


    public List<DateTimeNode> getParseDate() {
        String sourceText = getSourceText();
        List<DateTimeNode> dateTimeNodes = parseDate(sourceText);
        if (dateTimeNodes != null) {
            Collections.sort(dateTimeNodes);
        }

        return dateTimeNodes;
    }

    public List<DateTimeNode> getParseTime() {
        List<DateTimeNode> dtns = new ArrayList<>();
        String sourceText = getSourceText();
        List<DateTimeNode> timeNodes = parseTime(sourceText);
        List<DateTimeNode> locatorNodes = parseTimeLocator(sourceText);

        if (timeNodes != null) {
            Collections.sort(timeNodes);
        }
        if (locatorNodes != null) {
            Collections.sort(locatorNodes);
        }

        if (locatorNodes != null) {
            locatorTimeNode(timeNodes, locatorNodes);
        }

        if (timeNodes != null) {
            dtns.addAll(timeNodes);
        }
        return dtns;
    }

}
